home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / ARPSample1.0b1 / ARPerations.c next >
Encoding:
Text File  |  1997-04-03  |  20.9 KB  |  668 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ARPerations.c
  3.  
  4.     Contains:    Standard high-level ARP operations.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. ///////////////////////////////////////////////////////////////////
  22. // Lots of standard OT constructs.
  23.  
  24. #include <OpenTransport.h>
  25. #include <OpenTptClient.h>
  26.  
  27. ///////////////////////////////////////////////////////////////////
  28. // Pick up the names of the standard OT modules.
  29.  
  30. #include <modnames.h>
  31.  
  32. ///////////////////////////////////////////////////////////////////
  33. // Pick up types and constants for I_STR ioctls.
  34.  
  35. #include <stropts.h>
  36.  
  37. ///////////////////////////////////////////////////////////////////
  38. // Pick up handle operations for ARPGetCacheReport.
  39.  
  40. #include <Memory.h>
  41.  
  42. ///////////////////////////////////////////////////////////////////
  43. // Standard C string operations.
  44.  
  45. #include <string.h>
  46.  
  47. ///////////////////////////////////////////////////////////////////
  48. // Constants and types for ARP module messages.
  49.  
  50. #include "OTARPModule.h"
  51.  
  52. ///////////////////////////////////////////////////////////////////
  53. // Our own prototypes.
  54.  
  55. #include "ARPerations.h"
  56.  
  57. ///////////////////////////////////////////////////////////////////
  58.  
  59. // The following equates are actually exported by <miioccom.h>, but
  60. //  they are commented out for some reason )-:  So instead of including
  61. //  <miioccom.h> we just define them again here.
  62.  
  63. #define MIOC_ND            'c'        /* ioctl's for Mentat's nd device */
  64.  
  65. // The following equates define the two "Name Dispatch" ioctls
  66. // for setting and getting OT internal parameters.
  67.  
  68. #define ND_GET            MIOC_CMD(MIOC_ND, 0)    /* Get a value */
  69. #define ND_SET            MIOC_CMD(MIOC_ND, 1)    /* Set a value */
  70.  
  71. // The name of the Name Dispatch variable you have to get in
  72. // order to get a dump of the ARP cache.
  73.  
  74. #define ARP_ND_CACHE_REPORT "arp_cache_report"
  75.  
  76. enum {
  77.     kARP_ND_CACHE_REPORT_Length = 17            // strlen(ARP_ND_CACHE_REPORT) + 1
  78. };
  79.  
  80. OSStatus ARPGetCacheReport(Handle cacheReport)
  81.     // See comment in header file.
  82. {
  83.     OSStatus err;
  84.     StreamRef arpStream;
  85.     struct strioctl nddIOCommand;
  86.     SInt32 i;
  87.     char ndCommandBuffer[kARP_ND_CACHE_REPORT_Length];
  88.     UInt32 realDataSize;
  89.     SInt8 cacheReportHandleState;
  90.     
  91.     // First open up a raw STREAMS connection to the ARP module.
  92.     
  93.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  94.     
  95.     if (err == noErr) {
  96.  
  97.         // Switch the stream in sync/blocking mode.  To make the
  98.         // code easier, we're going to do this synchronously.
  99.  
  100.         (void) OTStreamSetBlocking(arpStream);
  101.         (void) OTStreamSetSynchronous(arpStream);
  102.         
  103.         // Copy the name of the ND variable we're trying
  104.         // to get into our buffer.
  105.  
  106.         OTStrCopy(ndCommandBuffer, ARP_ND_CACHE_REPORT);
  107.     
  108.         // The ND_GET ioctl returns a value and sets ic_len.  A negative
  109.         //  value is an error and you can give up now (-:  The rule for
  110.         //  positive values is a bit weirder.  ic_len is always set
  111.         //  to the amount of data that is actually returned.  If the
  112.         //  data available exceeds the available buffer space (as
  113.         //  defined by the ic_len on input), the ioctl returns
  114.         //  a positive number that is the amount of buffer space
  115.         //  needed.  So we first call it with a minimal buffer
  116.         //  then give it the buffer space it requires.  Obviously
  117.         //  there's a concurrency race here, which we conveniently
  118.         //  ignore in this sample by return kEAGAINErr.
  119.  
  120.         // First get the size of data buffer we need to allocate by
  121.         // doing the ioctl with a small buffer and examining the result.
  122.         
  123.         nddIOCommand.ic_cmd = ND_GET;
  124.         nddIOCommand.ic_timout = 0;
  125.         nddIOCommand.ic_len = kARP_ND_CACHE_REPORT_Length;    // Length of ND name including...
  126.         nddIOCommand.ic_dp = ndCommandBuffer;                // ...the zero terminator.
  127.         
  128.         err = OTStreamIoctl(arpStream, I_STR, &nddIOCommand);
  129.  
  130.         if (err >= noErr) {
  131.  
  132.             if (err > noErr) {
  133.             
  134.                 // The first ioctl returned a positive number telling
  135.                 // us how big the data returned was.  We turn around
  136.                 // around make the ioctl again, this time passing
  137.                 // in an appropriately sized buffer.
  138.  
  139.                 realDataSize = err;
  140.                 SetHandleSize(cacheReport, realDataSize);
  141.                 err = MemError();
  142.                 
  143.                 if (err == noErr) {
  144.                     cacheReportHandleState = HGetState(cacheReport);
  145.                     HLock(cacheReport);
  146.                     
  147.                     OTStrCopy(*cacheReport, ARP_ND_CACHE_REPORT);
  148.  
  149.                     nddIOCommand.ic_cmd = ND_GET;
  150.                     nddIOCommand.ic_timout = 0;
  151.                     nddIOCommand.ic_len = realDataSize;
  152.                     nddIOCommand.ic_dp = *cacheReport;
  153.  
  154.                     err = OTStreamIoctl(arpStream, I_STR, &nddIOCommand);
  155.                     
  156.                     HSetState(cacheReport, cacheReportHandleState);
  157.                 }
  158.             }
  159.             
  160.             if (err == noErr) {
  161.             
  162.                 // Everything is cool, we have the ARP report.  Now
  163.                 // all we have remaining is a trivial format
  164.                 // conversion.  The format returned is straight
  165.                 // text with zero characters as the line terminator.
  166.                 // We mutate the line terminators into Mac standard
  167.                 // CRs.
  168.                 
  169.                 for (i = 0; i < realDataSize; i++) {
  170.                     if ( (*cacheReport)[i] == 0 ) {
  171.                         (*cacheReport)[i] = 13;
  172.                     }
  173.                 }
  174.                 
  175.             } else {
  176.                 // Whoah, ARP table changed size!
  177.                 err = kEAGAINErr;
  178.             }
  179.         }
  180.     }
  181.     
  182.     // Clean up.
  183.     
  184.     if (arpStream != nil) {
  185.         (void) OTStreamClose(arpStream);
  186.     }
  187.     return (err);
  188. }
  189.  
  190. ///////////////////////////////////////////////////////////////////
  191.  
  192. // The following routines are used to copy variable length data structures
  193. // in the ARP command block that we're assembling.
  194.  
  195. static void CopyIntoCommandBuffer(char *buffer, UInt32 *currentOffset, void *data, UInt32 dataLength)
  196.     // Copy dataLength bytes from data into an ARP command buffer.
  197.     // buffer is a pointer to an ARP command block.
  198.     // currentOffset comes in as the number of bytes that are currently being
  199.     // used in the block, and is adjusted to represent the number of bytes we copied in.
  200.     // data is the address of the bytes to copy in.
  201.     // dataLength is the number of bytes to copy in.
  202. {
  203.     OTMemcpy(&buffer[*currentOffset], data, dataLength);
  204.     (*currentOffset) += dataLength;
  205. }
  206.  
  207. static void CopyInterfaceIntoCommandBuffer(char *buffer, UInt32 *currentOffset, char *interfaceName)
  208.     // Copy an interface name into an ARP command buffer.
  209.     // buffer is a pointer to an ARP command block.  This is assumed to point
  210.     // to at least an arc_t, although the other ARP command structures all
  211.     // begin with an arc_t, so it works for the other structures as well.
  212.     // currentOffset comes in as the number of bytes that are currently being
  213.     // used in the block, and is adjusted to represent the number of bytes we copied in.
  214.     // interfaceName is the address of a C string.
  215. {
  216.     arc_t *arpCommandPtr;
  217.     UInt32 interfaceNameLength;
  218.     
  219.     interfaceNameLength = OTStrLength(interfaceName) + 1;    // copy the string and the final null
  220.     arpCommandPtr = (arc_t *) buffer;
  221.     arpCommandPtr->arc_name_offset = *currentOffset;
  222.     arpCommandPtr->arc_name_length = interfaceNameLength;
  223.     CopyIntoCommandBuffer(buffer, currentOffset, interfaceName, interfaceNameLength);
  224. }
  225.  
  226. static void CopyProtoIntoCommandBuffer(char *buffer, UInt32 *currentOffset,
  227.                                         void *protoAddress, UInt32 protoSize)
  228.     // Copy an protocol address into an ARP command buffer.
  229.     // buffer is a pointer to an ARP command block.  This is assumed to point
  230.     // to at least an arc_t, although the other ARP command structures all
  231.     // begin with an arc_t, so it works for the other structures as well.
  232.     // currentOffset comes in as the number of bytes that are currently being
  233.     // used in the block, and is adjusted to represent the number of bytes we copied in.
  234.     // protoAddress is the address of the bytes of the protocol address to copy in.
  235.     // protoSize is the number of bytes to copy in.
  236. {
  237.     arc_t *arpCommandPtr;
  238.     
  239.     arpCommandPtr = (arc_t *) buffer;
  240.     arpCommandPtr->arc_proto_addr_offset = *currentOffset;
  241.     arpCommandPtr->arc_proto_addr_length = protoSize;
  242.     CopyIntoCommandBuffer(buffer, currentOffset, protoAddress, protoSize);
  243. }
  244.  
  245. ///////////////////////////////////////////////////////////////////
  246.  
  247. OSStatus ARPAddEntry(char *interfaceName,
  248.                         UInt32 arpProto,
  249.                         UInt32 flags,
  250.                         void *protoAddress, UInt32 protoSize, void *protoMask,
  251.                         void *hardwareAddress, UInt32 hardwareSize)
  252.     // See comment in header file.
  253. {
  254.     OSStatus err;
  255.     StreamRef arpStream;
  256.     char arpCommandBuffer[256];
  257.     area_t *arpAddCommandPtr;
  258.     UInt32 currentOffset;
  259.     struct strioctl arpIOControl;
  260.  
  261.     // First up, open a simple stream to the ARP as a driver.
  262.  
  263.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  264.     
  265.     if (err == noErr) {
  266.         (void) OTStreamSetBlocking(arpStream);
  267.         (void) OTStreamSetSynchronous(arpStream);
  268.  
  269.         // Initialise the command buffer for this command.
  270.  
  271.         arpAddCommandPtr = (area_t *) &arpCommandBuffer[0];
  272.         currentOffset = sizeof(area_t);
  273.  
  274.         arpAddCommandPtr->area_arc.arc_cmd = AR_ENTRY_ADD;
  275.         
  276.         CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
  277.             
  278.         arpAddCommandPtr->area_arc.arc_proto = arpProto;
  279.         
  280.         CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
  281.  
  282.         arpAddCommandPtr->area_arc.arc_flags = flags;
  283.         arpAddCommandPtr->area_arc.arc_client_q = nil;    // ignored by ARP for this command
  284.  
  285.         arpAddCommandPtr->area_proto_mask_offset = currentOffset;
  286.         CopyIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoMask, protoSize);
  287.         
  288.         arpAddCommandPtr->area_hw_addr_offset = currentOffset;
  289.         arpAddCommandPtr->area_hw_addr_length = hardwareSize;
  290.         CopyIntoCommandBuffer(arpCommandBuffer, ¤tOffset, hardwareAddress, hardwareSize);
  291.  
  292.         // Initialise the I_STR ioctl structure.
  293.  
  294.         arpIOControl.ic_cmd = AR_ENTRY_ADD;
  295.         arpIOControl.ic_timout = 0;
  296.         arpIOControl.ic_len = currentOffset;
  297.         arpIOControl.ic_dp = &arpCommandBuffer[0];
  298.         
  299.         // Send the ioctl.
  300.  
  301.         err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
  302.     }
  303.  
  304.     // Clean up.
  305.     
  306.     if (arpStream != nil) {
  307.         (void) OTStreamClose(arpStream);
  308.     }
  309.     return (err);
  310. }
  311.  
  312. ///////////////////////////////////////////////////////////////////
  313.  
  314. OSStatus ARPDeleteEntry(char *interfaceName,
  315.                         UInt32 arpProto,
  316.                         void *protoAddress, UInt32 protoSize)
  317.     // See comment in header file.
  318. {
  319.     OSStatus err;
  320.     StreamRef arpStream;
  321.     char arpCommandBuffer[256];
  322.     arc_t *arpDeleteCommandPtr;
  323.     UInt32 currentOffset;
  324.     struct strioctl arpIOControl;
  325.  
  326.     // First up, open a simple stream to the ARP as a driver.
  327.  
  328.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  329.     
  330.     if (err == noErr) {
  331.         (void) OTStreamSetBlocking(arpStream);
  332.         (void) OTStreamSetSynchronous(arpStream);
  333.  
  334.         // Initialise the command buffer for this command.
  335.  
  336.         arpDeleteCommandPtr = (arc_t *) &arpCommandBuffer[0];
  337.         currentOffset = sizeof(arc_t);
  338.  
  339.         arpDeleteCommandPtr->arc_cmd = AR_ENTRY_DELETE;
  340.         
  341.         CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
  342.             
  343.         arpDeleteCommandPtr->arc_proto = arpProto;
  344.         
  345.         CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
  346.  
  347.         arpDeleteCommandPtr->arc_flags = 0;            // ignored by ARP for this command
  348.         arpDeleteCommandPtr->arc_client_q = nil;    // ignored by ARP for this command
  349.  
  350.         // Initialise the I_STR ioctl structure.
  351.  
  352.         arpIOControl.ic_cmd = AR_ENTRY_DELETE;
  353.         arpIOControl.ic_timout = 0;
  354.         arpIOControl.ic_len = currentOffset;
  355.         arpIOControl.ic_dp = &arpCommandBuffer[0];
  356.         
  357.         // Send the ioctl.
  358.  
  359.         err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
  360.     }
  361.  
  362.     // Clean up.
  363.     
  364.     if (arpStream != nil) {
  365.         (void) OTStreamClose(arpStream);
  366.     }
  367.     return (err);
  368. }
  369.  
  370. ///////////////////////////////////////////////////////////////////
  371.  
  372. OSStatus ARPCacheQuery(char *interfaceName,
  373.                         UInt32 arpProto,
  374.                         void *protoAddress, UInt32 protoSize,
  375.                         void *hardwareAddress, UInt32 hardwareSize, UInt32 *flags)
  376.     // See comment in header file.
  377. {
  378.     OSStatus err;
  379.     StreamRef arpStream;
  380.     char arpCommandBuffer[256];
  381.     area_t *arpQueryCommandPtr;
  382.     UInt32 currentOffset;
  383.     struct strioctl arpIOControl;
  384.     
  385.     // First up, open a simple stream to the ARP as a driver.
  386.     
  387.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  388.     
  389.     if (err == noErr) {
  390.         (void) OTStreamSetBlocking(arpStream);
  391.         (void) OTStreamSetSynchronous(arpStream);
  392.  
  393.         // Initialise the command buffer for this command.
  394.  
  395.         arpQueryCommandPtr = (area_t *) &arpCommandBuffer[0];
  396.         currentOffset = sizeof(area_t);
  397.  
  398.         arpQueryCommandPtr->area_arc.arc_cmd = AR_ENTRY_SQUERY;
  399.         
  400.         CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
  401.             
  402.         arpQueryCommandPtr->area_arc.arc_proto = arpProto;
  403.         
  404.         CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
  405.  
  406.         arpQueryCommandPtr->area_arc.arc_flags = 0;            // return value
  407.         arpQueryCommandPtr->area_arc.arc_client_q = nil;    // ignored by ARP for this command
  408.  
  409.         arpQueryCommandPtr->area_proto_mask_offset = 0;        // ignored by ARP for this command
  410.         
  411.         arpQueryCommandPtr->area_hw_addr_offset = currentOffset;
  412.         arpQueryCommandPtr->area_hw_addr_length = hardwareSize;
  413.         currentOffset += hardwareSize;                        // space for return value
  414.  
  415.         // Initialise the I_STR ioctl structure.
  416.  
  417.         arpIOControl.ic_cmd = AR_ENTRY_SQUERY;
  418.         arpIOControl.ic_timout = 0;
  419.         arpIOControl.ic_len = currentOffset;
  420.         arpIOControl.ic_dp = &arpCommandBuffer[0];
  421.         
  422.         // Send the ioctl.
  423.         
  424.         err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
  425.     }
  426.     if (err == noErr) {
  427.  
  428.         // Copy results out to client buffer.
  429.         
  430.         OTMemcpy( hardwareAddress,                                                    // dest
  431.                     &arpCommandBuffer[arpQueryCommandPtr->area_hw_addr_offset],        // source
  432.                     hardwareSize);                                                    // length
  433.         *flags = arpQueryCommandPtr->area_arc.arc_flags;
  434.     }
  435.     
  436.     // Clean up.
  437.     
  438.     if (arpStream != nil) {
  439.         (void) OTStreamClose(arpStream);
  440.     }
  441.     return (err);
  442. }
  443.  
  444. ///////////////////////////////////////////////////////////////////
  445.  
  446. // The ARPInterfaceInfo structure is used to record all the information this
  447. // module stores about an interface that it brings up.  When
  448. // you call ARPInterfaceUp, the interfaceCookie result is really
  449. // a pointer to one of these structures.
  450.  
  451. struct ARPInterfaceInfo {
  452.     StreamRef interfaceStream;        // The ARP stream for the interface.
  453.     char interfaceName[256];        // The interface name, as calculated by GetARPInterfaceName.
  454. };
  455. typedef struct ARPInterfaceInfo ARPInterfaceInfo, *ARPInterfaceInfoPtr;
  456.  
  457. static OSStatus GetARPInterfaceName(ARPInterfaceInfoPtr interfaceInfo)
  458.     // Get the name for an interface on which we're about to bring up
  459.     // ARP.  ARP forms the interface name by taking the name of the module
  460.     // and appending a number, starting at 0, to make it unique.  Unfortunately
  461.     // we have no way of determining which interfaces are already in use
  462.     // by ARP, so we can't tell what number it will assign.  Therefore
  463.     // this sample just takes a guess, assuming 0.
  464.     // The routine gets the name of the module using the I_LIST ioctl,
  465.     // which returns a list of the module names on a stream, and looking
  466.     // for the last module name in the stream, ie the driver.  There
  467.     // really shouldn't be more than one module in the stream, so the
  468.     // array of 10 str_mlist we allocate for the return result should be
  469.     // more than enough.
  470. {
  471.     OSStatus err;
  472.     struct str_list streamList;
  473.     struct str_mlist streamListNames[10];
  474.     
  475.     streamList.sl_nmods = 10;
  476.     streamList.sl_modlist = streamListNames;
  477.     err = OTStreamIoctl(interfaceInfo->interfaceStream, I_LIST, &streamList);
  478.     if (err >= noErr) {
  479.         if ( streamList.sl_nmods == 0 ) {
  480.             err = -5;
  481.         } else {
  482.             OTStrCopy(interfaceInfo->interfaceName, streamListNames[ streamList.sl_nmods-1 ].l_name );
  483.             OTStrCat(interfaceInfo->interfaceName, "0");
  484.         }
  485.     }
  486.     
  487.     return (err);
  488. }
  489.  
  490. static OSStatus SendARPInterfaceUpDown(ARPInterfaceInfoPtr interfaceInfo, UInt32 arpCommand)
  491.     // Send an AR_INTERFACE_UP or AR_INTERFACE_DOWN command to the
  492.     // ARP interface we just created.  The name of the interface
  493.     // and the controlling stream for the interface are contained
  494.     // in the interfaceInfo pointer.  arpCommand is the actual
  495.     // command to send, ie either AR_INTERFACE_UP or AR_INTERFACE_DOWN.
  496. {
  497.     OSStatus err;
  498.     char arpCommandBuffer[256];
  499.     arc_t *arpCommandPtr;
  500.     UInt32 currentOffset;
  501.     struct strioctl arpIOControl;
  502.     
  503.     // Initialise the command buffer for this command.
  504.     
  505.     arpCommandPtr = (arc_t *) &arpCommandBuffer[0];
  506.     currentOffset = sizeof(arc_t);
  507.  
  508.     arpCommandPtr->arc_cmd = arpCommand;
  509.     
  510.     CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceInfo->interfaceName);
  511.         
  512.     arpCommandPtr->arc_proto = 0;                // ignored by ARP for this command
  513.     
  514.     arpCommandPtr->arc_proto_addr_offset = 0;    // ignored by ARP for this command
  515.     arpCommandPtr->arc_proto_addr_length = 0;    // ignored by ARP for this command
  516.  
  517.     arpCommandPtr->arc_flags = 0;                // ignored by ARP for this command
  518.     arpCommandPtr->arc_client_q = nil;            // ignored by ARP for this command
  519.  
  520.     // Initialise the I_STR ioctl structure.
  521.  
  522.     arpIOControl.ic_cmd = arpCommand;
  523.     arpIOControl.ic_timout = 0;
  524.     arpIOControl.ic_len = currentOffset;
  525.     arpIOControl.ic_dp = &arpCommandBuffer[0];
  526.     
  527.     // Send the ioctl.
  528.     
  529.     err = OTStreamIoctl(interfaceInfo->interfaceStream, I_STR, &arpIOControl);
  530.     
  531.     return (err);
  532. }
  533.  
  534. OSStatus ARPInterfaceUp(char *configString, UInt32 *interfaceCookie)
  535.     // See comment in header file.
  536. {
  537.     OSStatus err;
  538.     ARPInterfaceInfoPtr interfaceInfo;
  539.     OTConfiguration *arpConfig;
  540.     
  541.     // Prepare for failure.
  542.     
  543.     arpConfig = nil;
  544.     
  545.     // Create a record which we use to hold all the information
  546.     // about this interface.  The address of this record is passed
  547.     // back to the client as the interfaceCookie.
  548.     
  549.     err = noErr;
  550.     interfaceInfo = (ARPInterfaceInfoPtr) OTAllocMem(sizeof(ARPInterfaceInfo));
  551.     if ( interfaceInfo == nil) {
  552.         err = kENOMEMErr;
  553.     } else {
  554.         OTMemzero(interfaceInfo, sizeof(ARPInterfaceInfo));
  555.     }
  556.     
  557.     // Now create a configuration from the supplied configString...
  558.     
  559.     if (err == noErr) {
  560.         arpConfig = OTCreateConfiguration(configString);
  561.         if (arpConfig == kOTNoMemoryConfigurationPtr) {
  562.             err = kENOMEMErr;
  563.         } else if (arpConfig == kOTInvalidConfigurationPtr) {
  564.             err = kENXIOErr;
  565.         }
  566.     }
  567.  
  568.     // ... and push the ARP module on top of this configuration.
  569.     // Don't ask me why you have to do this or I'll start to
  570.     // whimper.
  571.     
  572.     if (err == noErr) {
  573.         (void) OTCfigPushParent(arpConfig, MI_ARPM_NAME, &err);
  574.     }
  575.     
  576.     // Now create a stream to device driver over which we'll
  577.     // be running ARP.  Note the use OTCreateStream rather than
  578.     // OTStreamOpen.  This is because the device driver might
  579.     // have extra plumbing underneath it (eg an ATM LANE emulation
  580.     // driver running over an ATM hardware driver), and just
  581.     // opening the driver would not give the driver's configurator
  582.     // chance to set up this plumbing.
  583.     
  584.     if (err == noErr) {
  585.         interfaceInfo->interfaceStream = OTCreateStream(arpConfig, 0, &err);
  586.         if (err != noErr) {
  587.             // Most OT create/open routines seem to return nil if they fail
  588.             // with an error, however it seems that OTCreateSteam is not
  589.             // as friendly.  So if we get an error we nil out our record
  590.             // of the stream to avoid trying to OTStreamClose a bogus stream
  591.             // as we clean up.
  592.             interfaceInfo->interfaceStream = nil;
  593.         }
  594.         arpConfig = nil;
  595.     }
  596.     
  597.     // Get the name of the interface that ARP will create when
  598.     // we start running it over our newly created stream.
  599.  
  600.     if (err == noErr) {
  601.         (void) OTStreamSetBlocking(interfaceInfo->interfaceStream);
  602.         (void) OTStreamSetSynchronous(interfaceInfo->interfaceStream);
  603.         err = GetARPInterfaceName(interfaceInfo);
  604.     }
  605.     
  606.     // Push ARP on top of the driver stream and then tell it that
  607.     // the corresponding interface is up.  ARP will then consider
  608.     // the interface to be active.  It will snarf ARP responses
  609.     // as they go across the network, and you can use the
  610.     // cache query, add and remove commands on that interface.
  611.     
  612.     if (err == noErr) {
  613.         err = OTStreamIoctl(interfaceInfo->interfaceStream, I_PUSH, MI_ARPM_NAME);
  614.     }
  615.     if (err == noErr) {
  616.         err = SendARPInterfaceUpDown(interfaceInfo, AR_INTERFACE_UP);
  617.     }
  618.     
  619.     // Clean up after failure.
  620.     
  621.     if (err != noErr) {
  622.         if (interfaceInfo != nil) {
  623.             if ( interfaceInfo->interfaceStream != nil ) {
  624.                 OTStreamClose( interfaceInfo->interfaceStream );
  625.             }
  626.             OTFreeMem(interfaceInfo);
  627.             interfaceInfo = nil;
  628.         }
  629.     }
  630.     
  631.     // General clean up.
  632.     
  633.     if (arpConfig != nil) {
  634.         OTDestroyConfiguration(arpConfig);
  635.     }
  636.     
  637.     // Regardless of error result, copy interfaceInfo out to client buffer.
  638.     // This ensures that the client gets a nil cookie when we get an error.
  639.     
  640.     *interfaceCookie = (UInt32) interfaceInfo;
  641.  
  642.     return (err);
  643. }
  644.  
  645. ///////////////////////////////////////////////////////////////////
  646.  
  647. OSStatus ARPInterfaceDown(UInt32 interfaceCookie)
  648.     // See comment in header file.
  649. {
  650.     OSStatus err;
  651.     ARPInterfaceInfoPtr interfaceInfo;
  652.     
  653.     interfaceInfo = (ARPInterfaceInfoPtr) interfaceCookie;
  654.     
  655.     // First tell ARP we're about to bring the interface down.
  656.     
  657.     err = SendARPInterfaceUpDown(interfaceInfo, AR_INTERFACE_DOWN);
  658.     
  659.     // Now close the stream that we opened to run the interface
  660.     // over.
  661.     if (err == noErr) {
  662.         (void) OTStreamClose( interfaceInfo->interfaceStream );
  663.         OTFreeMem(interfaceInfo);
  664.     }
  665.     
  666.     return (err);
  667. }
  668.